#include <driver/i2s.h>
#include <SD.h>
#include <SPI.h>

// SD 卡引脚定义
#define SD_MISO 9
#define SD_MOSI 10
#define SD_SCK 11
#define SD_CS 12

// I2S 引脚定义
#define I2S_WS 40
#define I2S_SCK 39
#define I2S_SD 38

// INMP441 配置
#define I2S_IN_PORT I2S_NUM_0
#define I2S_IN_BCLK 39
#define I2S_IN_LRC 40
#define I2S_IN_DIN 38

// 录音参数
#define RECORD_TIME 15        // 录音时长（秒）
#define WAV_FILE_NAME "data"  // WAV 文件基础名
#define SAMPLE_RATE 16000U    // 采样率
#define SAMPLE_BITS 24        // 位深度（24 位）
#define WAV_HEADER_SIZE 44    // WAV 文件头大小
u8_t VOLUME_GAIN = 30;        // 增益（1 表示无增益）

int fileNumber = 1;
String baseFileName;
bool isRecording = false;
File file;

void setup() {
  Serial.begin(115200);
  while (!Serial)
    ;

  // 初始化 I2S
  i2s_config_t i2s_config_in = {
    .mode = i2s_mode_t(I2S_MODE_MASTER | I2S_MODE_RX),  // 接收模式
    .sample_rate = SAMPLE_RATE,                         // 采样率
    .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT,       // 32 位采样
    .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,       // 单声道（右声道）
    .communication_format = i2s_comm_format_t(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB),
    .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,  // 中断优先级
    .dma_buf_count = 8,                        // DMA 缓冲区数量
    .dma_buf_len = 64                          // 每缓冲区长度
  };
  i2s_pin_config_t pin_config_in = {
    .bck_io_num = I2S_IN_BCLK,
    .ws_io_num = I2S_IN_LRC,
    .data_out_num = -1,
    .data_in_num = I2S_IN_DIN
  };
  i2s_driver_install(I2S_IN_PORT, &i2s_config_in, 0, NULL);
  i2s_set_pin(I2S_IN_PORT, &pin_config_in);

  // 初始化 SD 卡
  SPIClass pinconfig;
  pinconfig.begin(SD_SCK, SD_MISO, SD_MOSI, SD_CS);
  if (!SD.begin(SD_CS, pinconfig)) {
    Serial.println("Failed to mount SD Card!");
    while (1)
      ;
  }
  Serial.println("SD Card initialized. Enter label name:");
  while (true)
    _loop();
}

void _loop() {
  if (Serial.available() > 0) {
    String command = Serial.readStringUntil('\n');
    command.trim();
    if (command == "rec") {
      isRecording = true;
    } else if (command.indexOf("index") == 0) {
      String rec = command.substring(5);
      fileNumber = rec.toInt();
      Serial.println("INDEX=" + String(fileNumber));
    } else if (command.indexOf("gain") == 0) {
      String rec = command.substring(4);
      VOLUME_GAIN = rec.toInt();
      Serial.println("GAIN=" + String(VOLUME_GAIN));
    } else {
      baseFileName = command;
      fileNumber = 1;  // 重置文件编号
      Serial.println("Send 'rec' to start recording.");
    }
  }

  if (isRecording && baseFileName != "") {
    String fileName = "/" + baseFileName + "." + String(fileNumber) + ".wav";
    fileNumber++;
    file = SD.open(fileName, FILE_WRITE);
    if (!file) {
      Serial.println("Failed to open file for writing!");
      while (1)
        ;
    }
    record_wav(file, fileName);
    file.close();
    Serial.println("Recording complete.");
    delay(1000);  // 避免短时间内重复录音
    isRecording = false;
  }
}

void record_wav(File &file, String fileName) {
  uint32_t sample_size = 0;
  uint32_t record_size = SAMPLE_RATE * RECORD_TIME * 4;     // 32位采样率 4字节
  int32_t *rec_buffer = (int32_t *)ps_malloc(record_size);  // 32 位缓存
  if (!rec_buffer) {
    Serial.println("Memory allocation failed!");
    while (1)
      ;
  }

  uint8_t wav_header[WAV_HEADER_SIZE];
  generate_wav_header(wav_header, record_size, SAMPLE_RATE);
  file.write(wav_header, WAV_HEADER_SIZE);

  Serial.println("Recording...");
  i2s_read(I2S_IN_PORT, rec_buffer, record_size, &sample_size, portMAX_DELAY);
  if (sample_size == 0) {
    Serial.println("Recording failed!");
    free(rec_buffer);
    return;
  }

  for (int i = 0; i < sample_size / 4; ++i) {
    rec_buffer[i] *= VOLUME_GAIN;  // 增益
    //RIGHT
    //只写入头部两字节数据
    int16_t storage_sample = rec_buffer[i] >> 16;
    file.write((uint8_t *)&storage_sample, 2);
  }

  free(rec_buffer);
  Serial.println("Recording done!");
}


void generate_wav_header(uint8_t *wav_header, uint32_t wav_size, uint32_t sample_rate) {
  uint32_t file_size = wav_size + WAV_HEADER_SIZE - 8;
  uint32_t byte_rate = sample_rate * 2;  // 每帧占 2 字节
  const uint8_t set_wav_header[] = {
    'R', 'I', 'F', 'F',
    file_size, file_size >> 8, file_size >> 16, file_size >> 24,
    'W', 'A', 'V', 'E',
    'f', 'm', 't', ' ',
    0x10, 0x00, 0x00, 0x00,
    0x01, 0x00,  // PCM 格式
    0x01, 0x00,  // 单声道
    sample_rate, sample_rate >> 8, sample_rate >> 16, sample_rate >> 24,
    byte_rate, byte_rate >> 8, byte_rate >> 16, byte_rate >> 24,  // 字节率更新
    0x02, 0x00,                                                   // BlockAlign 每帧对齐大小（2 字节）
    0x10, 0x00,                                                   // BitsPerSample 设置为 16 位（尽管原始数据是 24 位）
    'd', 'a', 't', 'a',
    wav_size, wav_size >> 8, wav_size >> 16, wav_size >> 24
  };
  memcpy(wav_header, set_wav_header, sizeof(set_wav_header));
}


// void generate_wav_header(uint8_t *wav_header, uint32_t wav_size, uint32_t sample_rate) {
//   uint32_t file_size = wav_size + WAV_HEADER_SIZE - 8;
//   uint32_t byte_rate = sample_rate * 3;  // 每个采样点占 3 字节
//   const uint8_t set_wav_header[] = {
//     'R', 'I', 'F', 'F',                                                   // ChunkID
//     file_size, file_size >> 8, file_size >> 16, file_size >> 24,          // ChunkSize
//     'W', 'A', 'V', 'E',                                                   // Format
//     'f', 'm', 't', ' ',                                                   // Subchunk1ID
//     0x10, 0x00, 0x00, 0x00,                                               // Subchunk1Size
//     0x01, 0x00,                                                           // AudioFormat
//     0x01, 0x00,                                                           // NumChannels
//     sample_rate, sample_rate >> 8, sample_rate >> 16, sample_rate >> 24,  // SampleRate
//     byte_rate, byte_rate >> 8, byte_rate >> 16, byte_rate >> 24,          // ByteRate
//     0x03, 0x00,                                                           // BlockAlign
//     0x18, 0x00,                                                           // BitsPerSample (24 bits)
//     'd', 'a', 't', 'a',                                                   // Subchunk2ID
//     wav_size, wav_size >> 8, wav_size >> 16, wav_size >> 24               // Subchunk2Size
//   };
//   memcpy(wav_header, set_wav_header, sizeof(set_wav_header));
// }
void loop() {}